<?php
/**
 * mpPackager configuration.
 *
 * @category    Development
 * @package 	mpPackager
 * @subpackage  Configuration
 * @author		Murat Purc <murat@purc.de>
 * @copyright   Copyright (c) 2009-2010 Murat Purc (http://www.purc.de)
 * @license     http://www.gnu.org/licenses/gpl-2.0.html - GNU General Public License, version 2
 * @version     $Id: Config.php 4 2010-04-15 11:28:20Z purcaholic $
 */


/**
 * Configuration handler class.
 *
 * @category    Development
 * @package 	mpPackager
 * @subpackage  Configuration
 * @author		Murat Purc <murat@purc.de>
 */
class mpPackager_Config
{

    /**
     * Configuration list
     *
     * @var  array
     */
    private $_cfg = null;


    /**
     * Constructor, loads passed configuration file, checks settings and does
     * some preparations.
     *
     * @param   string  $configFile  Path to configuration file.
     */
    public function __construct($configFile)
    {
        // check configuration file
        // 1. filecheck with passed virgin file
        // 2. filecheck with prefixed packager dir
        $bak = array();
        if (!is_file($configFile)) {
            $bak[] = $configFile;
            $configFile = MPPACKAGER_DIR . $configFile;
        }
        if (!is_file($configFile)) {
            $bak[] = $configFile;
            throw new mpPackagerException('Could not found configuration file in ' . implode(" or ", $bak));
        }
        $cfg = parse_ini_file($configFile);

        // check source
        if (!isset($cfg['source'])) {
            throw new mpPackagerException('Missing source directory configuration');
        } elseif (!is_dir($cfg['source'])) {
            throw new mpPackagerException('Invalid source directory ' . $cfg['source']);
        }

        // check destination
        if (!isset($cfg['destination'])) {
            throw new mpPackagerException('Missing destination configuration');
        }

        // check ignoreDirs
        if (!isset($cfg['ignoreDirs'])) {
            throw new mpPackagerException('Missing ignoreDirs configuration');
        }
        $cfg['ignoreDirs'] = explode(',', $cfg['ignoreDirs']);
        foreach ($cfg['ignoreDirs'] as $p => $item) {
            $item = trim($item);
            if ($item  == '') {
                unset($cfg['ignoreDirs'][$p]);
            } else {
                $cfg['ignoreDirs'][$p] = $item;
            }
        }

        // check ignoreFiles
        if (!isset($cfg['ignoreFiles'])) {
            throw new mpPackagerException('Missing ignoreFiles configuration');
        }
        $cfg['ignoreFiles'] = explode(',', $cfg['ignoreFiles']);
        foreach ($cfg['ignoreFiles'] as $p => $item) {
            $item = trim($item);
            if ($item  == '') {
                unset($cfg['ignoreFiles'][$p]);
            } else {
                $cfg['ignoreFiles'][$p] = $item;
            }
        }

        // check replaceExts
        if (!isset($cfg['replaceExts'])) {
            throw new mpPackagerException('Missing replaceExts configuration');
        }
        $cfg['replaceExts'] = explode(',', $cfg['replaceExts']);
        foreach ($cfg['replaceExts'] as $p => $item) {
            $item = trim($item);
            if ($item  == '') {
                unset($cfg['replaceExts'][$p]);
            } else {
                $cfg['replaceExts'][$p] = $item;
            }
        }

        // extract replacement token
        $cfg['replacements'] = $this->_extractReplacements($cfg);

        // check folder perms
        if (!isset($cfg['folderPerms'])) {
            $cfg['folderPerms'] = 0755;
        }

        // check file perms
        if (!isset($cfg['filePerms'])) {
            $cfg['filePerms'] = 0644;
        }

        // check package list
        if (!isset($cfg['packageList'])) {
            throw new mpPackagerException('Missing packageList configuration');
        }

        // prepare package list
        $cfg['packageList'] = trim($cfg['packageList']);
        $cfg['packageList'] = str_replace("\r\n", "\n", $cfg['packageList']); // replace win -> unix
        $cfg['packageList'] = str_replace("\r", "\n", $cfg['packageList']);   // replace mac -> unix
        $cfg['packageList'] = preg_replace("/[\n\n]+/", "\n", $cfg['packageList']); // replace multiple line feeds
        $cfg['packageList'] = explode("\n", $cfg['packageList']);

        $this->_cfg = $cfg;
    }


    /**
     * Configuration item getter.
     *
     * @param   string  $key      Key of configuration to get
     * @param   mixed   $default  Default return value
     * @return  mixed
     */
    public function get($key, $default=null)
    {
        if (isset($this->_cfg[$key])) {
            return $this->_cfg[$key];
        } else {
            return $default;
        }
    }


    /**
     * Configuration item setter
     *
     * @param   string  $key    Key of configuration to set
     * @param   mixed   $value  Value to set
     * @return  void
     */
    public function set($key, $value)
    {
        $this->_cfg[$key] = $value;
    }


    /**
     * Extracts replacements from configuration.
     *
     * @param   array  $cfg  Assoziative configuration array
     * @return  array  Extracted assoziative replacements array as follows:
     *                 - $arr['tag_to_find'] = 'value_to_replace';
     */
    private function _extractReplacements(array $cfg)
    {
        // first loop to extract replacement entries
        $arr = array();
        foreach ($cfg as $key => $value) {
            if (strpos($key, 'replacements.') === 0) {
                $tmp = explode('.', $key);
                if (count($tmp) == 3) {
                    $arr[$tmp[1]][$tmp[2]] = $value;
                }
                unset($cfg[$key]);
            }
        }

        // second loop to process replacement entries
        $rep = array();
        foreach ($arr as $p => $item) {
            if (isset($item['search'])) {
                if (isset($item['replace'])) {
                    // static search and replace setting
                    $rep[$item['search']] = $item['replace'];
                } elseif (isset($item['callback']) && is_callable($item['callback'])) {
                    // dynamic search and replace setting with callback function
                    if (isset($item['param'])) {
                        $rep[$item['search']] = call_user_func($item['callback'], $item['param']);
                    } else {
                        $rep[$item['search']] = call_user_func($item['callback']);
                    }
                }
            }
        }

        return $rep;
    }

}
